#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include <math.h>

List *addTwoNumbers(Node *l1, Node *l2);

List *addTwoNumbers1(Node *l1, Node *l2);

List *addNumsToList(int *nums, int length);


__int128_t getRealNum(Node *node, int index);


int main() {
    int nums1[] = {
            2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3,
            2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 9};
    int nums2[] = {5, 6, 4, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2,
                   4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 2, 4, 3, 9, 9, 9, 9};


    List *list1 = addNumsToList(nums1, sizeof(nums1) / sizeof(int));
    List *list2 = addNumsToList(nums2, sizeof(nums2) / sizeof(int));

    List *list = addTwoNumbers(list1->header, list2->header);
    printList(list);

    list->clear(list);
    list = addTwoNumbers1(list1->header, list2->header);
    printList(list);
    list->clear(list);
    list1->clear(list1);
    list2->clear(list2);
    return 0;
}

List *addNumsToList(int *nums, int length) {
    List *list = create();
    for (int i = 0; i < length; ++i) {
        list->add(list, nums[i]);
    }
    printList(list);
    return list;
}

__int128_t getRealNum(Node *node, int index) {
    if (node != NULL) {
        __int128_t powNum = 1;
        for (int i = 1; i <= index; i++) {
            powNum *= 10;
        }
        return node->num * powNum;
    }
    return 0;
}

int addNum(Node *n1, Node *n2, int *sum, int carry) {
    int num1 = 0;
    int num2 = 0;
    if (n1 != NULL) {
        num1 = n1->num;
    }
    if (n2 != NULL) {
        num2 = n2->num;
    }

    *sum = num1 + num2 + carry;
    return *sum >= 10 ? 1 : 0;
}

List *addTwoNumbers1(Node *l1, Node *l2) {
    __int128_t sum = 0;
    Node *t1 = l1;
    Node *t2 = l2;
    int index = 0;
    while (t1 != NULL || t2 != NULL) {

        sum += getRealNum(t1, index);
        sum += getRealNum(t2, index);
        index++;
        if (t1 != NULL) {
            t1 = t1->next;
        }
        if (t2 != NULL) {
            t2 = t2->next;
        }
    }
    List *list = create();
    do {
        list->add(list, sum % 10);
        sum /= 10;
    } while (sum != 0);

    return list;
}

List *addTwoNumbers(Node *l1, Node *l2) {
    int *sum = (int *) malloc(sizeof(int));
    Node *t1 = l1;
    Node *t2 = l2;
    int carry = 0;
    List *list = create();
    while (t1 != NULL || t2 != NULL) {
        carry = addNum(t1, t2, sum, carry);
        list->add(list, *sum % 10);
        if (t1 != NULL) {
            t1 = t1->next;
        }
        if (t2 != NULL) {
            t2 = t2->next;
        }
    }
    if (carry == 1) {
        list->add(list, 1);
    }
    free(sum);
    sum = NULL;

    return list;
}